page.tsx 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632
  1. "use client";
  2. import {
  3. getCommissionApi,
  4. getRegisterCountApi,
  5. getTotalCountApi,
  6. getWithdrawalApi,
  7. } from "@/api/summary";
  8. import { useUserInfoStore } from "@/stores/useUserInfoStore";
  9. import { useRequest } from "ahooks";
  10. import { Mask, Toast } from "antd-mobile";
  11. import { useLocale, useTranslations } from "next-intl";
  12. import { CashbackTypes, Rule } from "@/api/cashback";
  13. import { CommissionModel } from "@/app/[locale]/affiliate/component/TabsCom";
  14. import Table, { TableHeaderItem } from "@/components/Table";
  15. import TipsModal, { ModalProps } from "@/components/TipsModal";
  16. import { server } from "@/utils/client";
  17. import { getToken } from "@/utils/Cookies";
  18. import { copyText } from "@/utils/methods";
  19. import Image from "next/image";
  20. import { FC, useEffect, useRef, useState } from "react";
  21. import "./page.scss";
  22. interface Props {}
  23. const RulesClient = () => {
  24. const t = useTranslations("cashback");
  25. const [rules, setRules] = useState<any[]>([]);
  26. const [visible, setVisible] = useState(false);
  27. const columns: TableHeaderItem[] = [
  28. {
  29. title: <div className={"text-center text-[#98a7b5]"}>Nivel Agente</div>,
  30. dataIndex: "level",
  31. align: "center",
  32. render: (item: Rule) => (
  33. <div className={"text-[0.12rem] text-[#98a7b5]"}>{item.level}</div>
  34. ),
  35. },
  36. {
  37. title: <div className={"text-center text-[#98a7b5]"}>Apostas Validas</div>,
  38. dataIndex: "aposta",
  39. align: "center",
  40. render: (item: Rule) => (
  41. <div className={"text-[0.12rem] text-[#98a7b5]"}>{item.aposta} Dez mil+</div>
  42. ),
  43. },
  44. {
  45. title: <div className={"text-center text-[#98a7b5]"}>Comissão</div>,
  46. dataIndex: "cashback",
  47. render: (item: Rule) => (
  48. <div className={"text-center text-[0.12rem] text-[#db922b]"}>
  49. {item.cashback}
  50. <span className={"text-[#98a7b5]"}>/Dez mill</span>
  51. </div>
  52. ),
  53. },
  54. ];
  55. const loadMore = async () => {
  56. return Promise.resolve();
  57. };
  58. const getCashBackApi = async () => {
  59. return server
  60. .request<CashbackTypes>({
  61. url: "/v1/api/front/activity_cash",
  62. method: "post",
  63. })
  64. .then((res) => {
  65. return res.data;
  66. })
  67. .catch((error) => {
  68. return {
  69. rules: [],
  70. last_period: { end_time: 0, start_time: 0 },
  71. next_period: {
  72. end_time: 0,
  73. start_time: 0,
  74. },
  75. amount: 0,
  76. bet: 0,
  77. status: "expired",
  78. };
  79. });
  80. };
  81. useEffect(() => {
  82. getCashBackApi().then((res) => {
  83. setRules(res.rules);
  84. });
  85. }, []);
  86. return (
  87. <div className={"text-[0.12rem]"}>
  88. <div className={"bg-[#0e1319] p-[0.0694rem]"}>
  89. <Table
  90. columns={columns}
  91. headerClassName={" bg-[#151d28] "}
  92. bodyClassName={"odd:bg-[#0e1319] even:bg-[#151d28]"}
  93. dataSource={rules || []}
  94. loadMore={loadMore}
  95. hasMore={false}
  96. isLoadMore={false}
  97. isBackground={false}
  98. />
  99. </div>
  100. <div className={"mt-[0.1389rem] flex items-center text-[#98a7b5]"}>
  101. <p
  102. className={"mr-[0.1389rem] h-[0.0694rem] w-[0.0694rem] rounded bg-[#98a7b5]"}
  103. ></p>{" "}
  104. A apostas válidas depende dos diferentes jogos:
  105. </div>
  106. <div className={"mt-[0.1389rem] flex bg-[#25262b] p-[0.1389rem] text-[#98a7b5]"}>
  107. <span className={"iconfont icon-tishi text-[0.10rem]"}></span>
  108. <div className={"ml-[0.0694rem]"}>
  109. Os tipos de crash e os jogos virtuais não serão considerados apostas válidas{" "}
  110. </div>
  111. </div>
  112. <div className={"mt-[0.1389rem] bg-[#25262b] p-[0.1389rem] text-[#98a7b5]"}>
  113. <div>
  114. <span className={"text-[0.22rem] text-[#fff]"}>100%</span>
  115. <span> De aposta </span>
  116. </div>
  117. <div>
  118. <span className={"text-[#575f6a]"}>Jogos : </span>
  119. <span> Live Casino, 3rd Party</span>
  120. </div>
  121. </div>
  122. <div className={"mt-[0.1389rem] bg-[#25262b] p-[20px] text-[#98a7b5]"}>
  123. <div>
  124. <span className={"text-[0.22rem] text-[#fff]"}>100%</span>
  125. <span> De aposta </span>
  126. </div>
  127. <div>
  128. <span className={"text-[#575f6a]"}>Jogos : </span>
  129. <span>Os outros jogos originais</span>
  130. </div>
  131. </div>
  132. <div
  133. onClick={() => setVisible(true)}
  134. className={
  135. "mt-[0.1389rem] flex justify-between bg-[#25262b] p-[0.1042rem] text-[#98a7b5]"
  136. }
  137. >
  138. Regras de cálculo de comissão
  139. <span className={"iconfont icon-xiangyou2"}></span>
  140. </div>
  141. <ul className={"ml-[0.1389rem] mt-[0.1389rem] list-disc text-[#98a7b5]"}>
  142. <li className={"mt-[0.0694rem]"}>
  143. As comissões podem ser retiradas em nossa carteira 8pg do painel a qualquer
  144. momento.
  145. </li>
  146. <li className={"mt-[0.0694rem]"}>O sistema calcula a comissão a cada 24 horas.</li>
  147. <li className={"mt-[0.0694rem]"}>Comissão máxima diária : 10000 BRL</li>
  148. <li className={"mt-[0.0694rem]"}>
  149. A comissão não será creditada para o mesmo IP ou dispositivo, e a inflação
  150. intencional do volume de negócios não será creditada para a comissão.{" "}
  151. </li>
  152. </ul>
  153. <CommissionModel visible={visible} setVisible={setVisible} />
  154. </div>
  155. );
  156. };
  157. const App: FC<Props> = (props) => {
  158. const t = useTranslations("SummaryPage");
  159. const locale = useLocale();
  160. const sliderRef = useRef<HTMLDivElement>(null);
  161. const [num, setNum] = useState(100);
  162. const [money, setMoney] = useState("5000");
  163. const [visible, setVisible] = useState(false);
  164. const todayModalRef = useRef<ModalProps>(null);
  165. const totalModalRef = useRef<ModalProps>(null);
  166. const { userInfo } = useUserInfoStore();
  167. const token = getToken();
  168. // 生成分享链接
  169. const BASE_URL = process.env.NEXT_PUBLIC_SHARE_URL;
  170. const shareUrl = `${BASE_URL}/${locale}/${userInfo ? userInfo.referrer_code : "xxxxxx"}`;
  171. const url = encodeURIComponent(`${shareUrl}`);
  172. const SHARE_SOURCE = [
  173. {
  174. icon: "/summary/Facebook.png",
  175. label: "Facebook",
  176. shareUrl: `https://www.facebook.com/sharer/sharer.php?u=${url}`,
  177. },
  178. {
  179. icon: "/summary/WhatsApp.png",
  180. label: "WhatsApp",
  181. shareUrl: `https://api.whatsapp.com/send?text=${url}`,
  182. },
  183. {
  184. icon: "/summary/Telegram.png",
  185. label: "Telegram",
  186. shareUrl: `https://t.me/share/url?url=${url}`,
  187. },
  188. {
  189. icon: "/summary/Twitter.png",
  190. label: "Twitter",
  191. shareUrl: `https://twitter.com/intent/tweet?text=${url}`,
  192. },
  193. {
  194. icon: "/summary/Email.png",
  195. label: "Email",
  196. shareUrl: `mailto: ?&subject=&cc=&bcc=&body=${url}`,
  197. },
  198. ];
  199. // 轮询时间
  200. const TIME = 180000;
  201. const getUserMoneyHandler = () => {
  202. if (token) {
  203. return getRegisterCountApi().then((res) => {
  204. if (res.code === 200) return res.data;
  205. });
  206. }
  207. return Promise.resolve({
  208. commissar: 0,
  209. effective_amount: 0,
  210. recharge_user_count: 0,
  211. reg_count: 0,
  212. });
  213. };
  214. const { data: todayData } = useRequest(getUserMoneyHandler, {
  215. pollingInterval: TIME,
  216. pollingWhenHidden: true,
  217. pollingErrorRetryCount: 3,
  218. staleTime: 5000,
  219. refreshDeps: [token],
  220. });
  221. const getTotalCount = () => {
  222. if (token) {
  223. return getTotalCountApi().then((res) => {
  224. if (res.code === 200) return res.data;
  225. });
  226. }
  227. return Promise.resolve({
  228. commissar: 0,
  229. effective_amount: 0,
  230. recharge_user_count: 0,
  231. reg_count: 0,
  232. });
  233. };
  234. const { data: totalData } = useRequest(getTotalCount, {
  235. pollingInterval: TIME,
  236. pollingWhenHidden: true,
  237. pollingErrorRetryCount: 3,
  238. staleTime: 5000,
  239. });
  240. const getCommission = () => {
  241. if (token) {
  242. return getCommissionApi().then((res) => {
  243. if (res.code === 200) return res.data;
  244. });
  245. }
  246. return Promise.resolve({
  247. commissar: 0,
  248. level: 0,
  249. withdrawal_commissions: 0,
  250. enable_receive: false,
  251. min_value: 0,
  252. max_value: 0,
  253. });
  254. };
  255. const { data: commissionData, run: commissionRun } = useRequest(getCommission, {
  256. pollingInterval: TIME,
  257. pollingWhenHidden: true,
  258. pollingErrorRetryCount: 3,
  259. staleTime: 5000,
  260. });
  261. const handleSlide: any = (e: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
  262. if (sliderRef.current) {
  263. const startX = sliderRef.current.getBoundingClientRect().x;
  264. const x = e.clientX - startX;
  265. const xRem = x / (144 * 0.6);
  266. const intNum = Math.round(10000 * xRem) - Math.round((10000 * xRem) % 10);
  267. setNum(intNum);
  268. const m = intNum * 50;
  269. let r = "";
  270. const arr = m.toString().split("");
  271. arr.forEach((item, i) => {
  272. if (i !== arr.length - 1 && (arr.length - i - 1) % 3 === 0) {
  273. r += item + ",";
  274. } else {
  275. r += item;
  276. }
  277. });
  278. setMoney(r);
  279. const scale = (Math.round(xRem * 10000) / 100.0).toFixed(2) + "%";
  280. sliderRef.current.style.width = scale;
  281. }
  282. };
  283. const copy = (text: string) => {
  284. copyText(text);
  285. Toast.show({ icon: "success", content: t("copySuc"), maskClickable: false });
  286. };
  287. const withdrawalHandler = async () => {
  288. if (commissionData === undefined) return;
  289. if (!commissionData.enable_receive) {
  290. Toast.show(t("receive"));
  291. return;
  292. }
  293. const commissar = commissionData.commissar ?? 0; // 使用空值合并运算符处理可能的 undefined
  294. const minValue = Math.min(commissionData.min_value, 10);
  295. if (commissar > minValue) {
  296. const available = Math.min(commissionData.max_value, commissar);
  297. getWithdrawalApi({ amount: available }).then((res) => {
  298. if (res.code === 200) {
  299. setTimeout(commissionRun, 200);
  300. }
  301. });
  302. return;
  303. } else {
  304. Toast.show(t("receive"));
  305. }
  306. };
  307. return (
  308. <div className="content">
  309. <div className="summary referral-router-view">
  310. <div className="content" style={{ marginTop: 0 }}>
  311. <div className="title">
  312. <div>
  313. {t("Hoje")}
  314. <span
  315. className="iconfont icon-bangzhu"
  316. onClick={() => todayModalRef.current?.onOpen()}
  317. />
  318. </div>
  319. </div>
  320. <div className="cardMian">
  321. <ul className="statistics-card">
  322. <li>
  323. <p className="num">{todayData?.reg_count}</p>
  324. <p> {t("Inscrições")} </p>
  325. </li>
  326. <li>
  327. <p className="num">{todayData?.recharge_user_count}</p>
  328. <p> {t("Novos")} </p>
  329. </li>
  330. <li>
  331. <p className="num">
  332. <span className={"mr-[5px]"}>{t("R$")}</span>
  333. {todayData?.effective_amount}
  334. </p>
  335. <p> {t("Aposta")} </p>
  336. </li>
  337. <li>
  338. <p className="num">
  339. <span className={"mr-[5px]"}>{t("R$")}</span>
  340. {todayData?.commissar}
  341. </p>
  342. <p> {t("Comissão")} </p>
  343. </li>
  344. </ul>
  345. </div>
  346. </div>
  347. <div className="content">
  348. <div className="title">
  349. <div>
  350. {t("Total")}
  351. <span
  352. className="iconfont icon-bangzhu"
  353. onClick={() => totalModalRef.current?.onOpen()}
  354. />
  355. </div>
  356. </div>
  357. <div className="cardMian">
  358. <ul className="statistics-card">
  359. <li>
  360. <p className="num">{totalData?.reg_count}</p>
  361. <p> {t("Inscrições")} </p>
  362. </li>
  363. <li>
  364. <p className="num">{totalData?.recharge_user_count}</p>
  365. <p> {t("Jogadores")} </p>
  366. </li>
  367. <li>
  368. <p className="num">
  369. <span className={"mr-[5px]"}>{t("R$")}</span>
  370. {totalData?.effective_amount}
  371. </p>
  372. <p> {t("ApostaTotal")} </p>
  373. </li>
  374. <li>
  375. <p className="num">
  376. <span className={"mr-[5px]"}>{t("R$")}</span>
  377. {totalData?.commissar}
  378. </p>
  379. <p>RS {t("Comissão")} </p>
  380. </li>
  381. </ul>
  382. </div>
  383. </div>
  384. <div className="content">
  385. <div className="title">
  386. <div>
  387. {t("Comissão")}
  388. <span
  389. className="iconfont icon-bangzhu"
  390. onClick={() => setVisible(true)}
  391. />
  392. </div>
  393. </div>
  394. <div className="cardMian">
  395. <div className="vip">
  396. <div className="level">
  397. {/*<span className="iconfont icon-vip"></span>*/}
  398. <Image
  399. src={"/summary/level.png"}
  400. alt={"level"}
  401. height={120}
  402. width={120}
  403. />
  404. <span className="levelNum">{commissionData?.level}</span>
  405. </div>
  406. <div>
  407. {t("Nível")}
  408. <span
  409. className="iconfont icon-tishi"
  410. onClick={() => setVisible(true)}
  411. ></span>
  412. </div>
  413. </div>
  414. <div>
  415. <ul className="commission">
  416. <li>
  417. <p className="num">
  418. <span>{t("R$")}</span>
  419. <span className="cash">
  420. {commissionData?.withdrawal_commissions}
  421. </span>
  422. </p>
  423. <p> {t("TotalPago")} </p>
  424. </li>
  425. <li>
  426. <p className="num">
  427. <span>{t("R$")}</span>
  428. <span className="cash">{commissionData?.commissar}</span>
  429. </p>
  430. <p> {t("Não")} </p>
  431. </li>
  432. </ul>
  433. <div className="wallet">
  434. <div className="btn" onClick={withdrawalHandler}>
  435. {t("TRANSFERIR")}
  436. </div>
  437. <div className="tip">
  438. <span className="iconfont icon-tishi1"></span>
  439. {t("Valor")}
  440. </div>
  441. </div>
  442. </div>
  443. </div>
  444. </div>
  445. <div className="content shareMain">
  446. <div className="title">
  447. <div>{t("title1")}</div>
  448. </div>
  449. <div className="share">
  450. <ul className="sharePlatform">
  451. {SHARE_SOURCE.map((item, index) => {
  452. return (
  453. <a
  454. href={item.shareUrl}
  455. key={index}
  456. target={"_blank"}
  457. className={"flex flex-col items-center"}
  458. >
  459. <Image
  460. src={item.icon}
  461. alt={"Mais"}
  462. width={70}
  463. height={70}
  464. />
  465. <p className={"mt-[0.0347rem] text-[12px] text-[#808080]"}>
  466. {item.label}
  467. </p>
  468. </a>
  469. );
  470. })}
  471. </ul>
  472. </div>
  473. <div className="shareLink">
  474. <div className="">{t("content1")}</div>
  475. <div className="copyUrl">
  476. <span className="url omitWrap">{shareUrl}</span>
  477. <span id="copy" onClick={() => copy(shareUrl)}>
  478. {t("Cópia")}
  479. </span>
  480. </div>
  481. </div>
  482. </div>
  483. <div className="content">
  484. <div className="title">
  485. <div> {t("title2")}</div>
  486. </div>
  487. <div>
  488. <div className="tel-box">
  489. <a href="" className="telicon">
  490. <Image
  491. src="/summary/telegram-nobg.png"
  492. height={100}
  493. width={100}
  494. alt="telegram"
  495. />
  496. </a>
  497. <div className="hintTitle3">{t("content2-1")}</div>
  498. </div>
  499. <div className="hintTitle2">
  500. <i className="iconfont icon-tishi"></i>
  501. {t("content2-2")}
  502. <a
  503. href=""
  504. style={{
  505. borderBottom: "1px solid rgb(109, 155, 195)",
  506. color: "#0000EE",
  507. }}
  508. >
  509. {t("business")}
  510. </a>
  511. </div>
  512. </div>
  513. </div>
  514. <div className="content">
  515. <div className="title">
  516. <div>
  517. {t("title3")}
  518. <span
  519. className="iconfont icon-bangzhu"
  520. onClick={() => setVisible(true)}
  521. ></span>
  522. </div>
  523. </div>
  524. <div className="hint">
  525. <div className="hintTitle">{t("content3")}</div>
  526. <div className="imgContent">
  527. <Image width={100} height={100} src="/summary/money.png" alt="" />
  528. <div>
  529. {t("number")}
  530. {num}
  531. <br />
  532. {t("Comissão")} &gt; {t("R$")} {money} {t("money")}
  533. </div>
  534. <div
  535. className="slider van-slider"
  536. style={{ height: "0.02rem" }}
  537. onClick={handleSlide}
  538. >
  539. <div
  540. className="van-slider__bar"
  541. style={{ width: "0.900901%", background: "rgb(0, 157, 128)" }}
  542. ref={sliderRef}
  543. >
  544. <div role="slider" className="van-slider__button-wrapper">
  545. <div className="img"></div>
  546. </div>
  547. </div>
  548. </div>
  549. </div>
  550. <div className="relationSchema">
  551. <div className="groupTitle">{t("title4")}</div>
  552. <img src="/summary/group_br.png" alt="" className="groupImg" />
  553. <ul className="rules">
  554. <li>
  555. {t("content4-1")}
  556. <span style={{ color: "red" }}>{t("red")}</span>.
  557. </li>
  558. <li>{t("content4-2")}</li>
  559. </ul>
  560. </div>
  561. </div>
  562. </div>
  563. <div className="content"></div>
  564. </div>
  565. <TipsModal title={t("modalTitle")} ref={todayModalRef}>
  566. <ul className={"list-decimal break-all p-[0.1389rem] pt-0 font-bold"}>
  567. <li>{t("todayDesc1")}</li>
  568. <li>{t("todayDesc2")}</li>
  569. <li>{t("todayDesc3")}</li>
  570. </ul>
  571. <p className={"text-[gray]"}>{t("modalTips")}</p>
  572. </TipsModal>
  573. <TipsModal title={t("modalTitle")} ref={totalModalRef}>
  574. <ul className={"list-decimal break-all p-[0.1389rem] pt-0 font-bold"}>
  575. <li>{t("totalDesc1")}</li>
  576. <li>{t("totalDesc2")}</li>
  577. <li>{t("totalDesc3")}</li>
  578. </ul>
  579. <p className={"text-[gray]"}>{t("modalTips")}</p>
  580. </TipsModal>
  581. <Mask visible={visible} getContainer={null}>
  582. <div className={"h-[100vh] w-[100%] overflow-scroll bg-[#1f2024]"}>
  583. <div
  584. className={
  585. "absolute top-0 flex items-center justify-between " +
  586. " h-[0.4167rem] w-[100%] border-[1px] bg-[#17181c] px-[0.1389rem]" +
  587. " z-10 border-[#666]"
  588. }
  589. >
  590. <p>Regras de recompensas por comissão</p>
  591. <i className={"iconfont icon-guanbi"} onClick={() => setVisible(false)}></i>
  592. </div>
  593. <div className={"mt-[0.4167rem] px-[0.1389rem] pt-[0.1389rem]"}>
  594. <RulesClient />
  595. </div>
  596. </div>
  597. </Mask>
  598. </div>
  599. );
  600. };
  601. export default App;